/*
 * author: 徐冉辰2021080908028
 */

#pragma once

#include <iostream>
#include <fstream>
#include <sstream>
#include <filesystem>
#include <iomanip>
#include <string>
#include <exception>
#include <stack>
#include <vector>
#include <set>
#include <utility>
#include <algorithm>
#include <stdexcept>

#include "../1-LexAnalysis/LexAnalysis.hpp"
#include "../TokenTable.h"

class Process
{
public:
    std::string pName;
    int firstVariable; /* 第一个变量在变量表中的位置 */
    int lastVariable;  /* 最后一个变量在变量表中的位置 */

    Process(std::string name)
        : pName(name), firstVariable(-1), lastVariable(-1) {}
};

/*
 * 语法分析器
 */
class SyntaxAnalysis
{
private:
    std::ifstream ifs_source;
    std::ofstream ofs_result, ofs_variable, ofs_process, ofs_error;

    std::vector<std::pair<std::string, int>> inputTokens;                  /* 存储 ifs_source */
    std::vector<std::pair<std::string, int>>::const_iterator currentToken; /* 指向下一个非 EOLN token */
    void loadData(std::filesystem::path sourceFile);
    bool matchTerminal(int terminal_type, int terminal_type2 = 0);
    bool searchTerminal(int terminal_type, int terminal_type2 = 0);
    void skipErrors();

    /* 解决变量重名 first.string:变量名 second.string:变量所在过程名 */
    std::set<std::pair<std::string, std::string>> VariablesTable;
    /* 解决过程重名 string:过程名 */
    std::set<std::string> ProcessesTable;
    /* 处理过程层级 size:过程层次 top:当前过程 */
    std::stack<Process> ProcessStack;
    void saveVariable(std::pair<std::string, std::string> variable_pair);
    void saveProcess(std::string process_name);
    void errorOutput(std::string error_type, std::string error_info);

    void parseProgram();
    void parseSubProgram();
    void parseDeclarationStatementList();
    void parseExecutionStatementList();
    void parseDeclarationStatement();
    void parseVariableDeclaration();
    bool parseVariable();
    void parseFunctionDeclaration();
    void parseParameter();
    void parseFunctionBody();
    void parseExecutionStatement();
    void parseReadStatement();
    void parseWriteStatement();
    void parseAssignmentStatement();
    void parseArithmeticExpression();
    void parseTerm();
    void parseFactor();
    void parseFunctionCall();
    void parseConditionalStatement();
    void parseConditionalExpression();

public:
    int token_number;
    int line_number;
    int error_number;

    SyntaxAnalysis() : token_number(0), line_number(0), error_number(0) {}
    ~SyntaxAnalysis();

    void parser(std::filesystem::path sourceFile);
};